﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Turquoise.Business.Abstract;
using Turquoise.Core.Entities;
using Turquoise.DataAccess.Abstract;
using Turquoise.DataAccess.Helpers;
using Turquoise.Entities.Complex.BaseModels;
using Turquoise.Entities.Data;
using Turquoise.Exceptions;
using Turquoise.Globalization;
using Turquoise.Helpers;
using Turquoise.Validation.FluentValidation.ContentTypeValidation;

namespace Turquoise.Business
{
    public class ContentTypeManager : IContentTypeService
    {

        private readonly IRepository<ContentType> _repository;
        private readonly IRepository<ContentTypeHistory> _historyRepository;
        private readonly IRepository<ContentTypeLanguageLineHistory> _lineHistoryRepository;
        private readonly ISettingService _settingService;
        private readonly ILanguageService _languageService;
        public ContentTypeManager(IRepository<ContentType> repository, ISettingService settingService, ILanguageService languageService, IRepository<ContentTypeHistory> historyRepository, IRepository<ContentTypeLanguageLineHistory> lineHistoryRepository)
        {
            _repository = repository;
            _settingService = settingService;
            _languageService = languageService;
            _historyRepository = historyRepository;
            _lineHistoryRepository = lineHistoryRepository;
        }
        public AddModel<ContentType> Add()
        {
            var languages = _languageService.GetAll();
            return new AddModel<ContentType>
            {
                Item = new ContentType
                {
                    ContentTypeLanguageLines = languages.Select(language => new ContentTypeLanguageLine
                    {
                        LanguageId = language.Id
                    }).ToList()
                },
                Languages = languages
            };
        }
        public void Add(AddModel<ContentType> model)
        {
            model.Languages = _languageService.GetAll();
            var validator = new AddValidator(model);
            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }
            var item = model.Item;
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            item.CreateDate = DateTime.Now;
            item.CreatedBy = identity.UserId;
            item.UpdatedBy = identity.UserId;
            item.UpdateDate = DateTime.Now;
            for (var i = 0; i < item.ContentTypeLanguageLines.Count; i++)
            {
                item.ContentTypeLanguageLines[i].CreateDate = DateTime.Now;
                item.ContentTypeLanguageLines[i].CreatedBy = identity.UserId;
                item.ContentTypeLanguageLines[i].UpdateDate = DateTime.Now;
                item.ContentTypeLanguageLines[i].UpdatedBy = identity.UserId;
                item.ContentTypeLanguageLines[i].LanguageId = model.Languages[i].Id;

            }
            var affectedItem = _repository.Add(item);
            foreach (var contentTypeLanguageLine in affectedItem.ContentTypeLanguageLines)
            {
                contentTypeLanguageLine.DisplayOrder = affectedItem.Id;
                _lineHistoryRepository.Add(new ContentTypeLanguageLineHistory
                {
                    ContentTypeLanguageLineId = contentTypeLanguageLine.Id,
                    ContentTypeId = contentTypeLanguageLine.ContentTypeId,
                    LanguageId = contentTypeLanguageLine.LanguageId,
                    ContentTypeName = contentTypeLanguageLine.ContentTypeName,
                    ContentTypeDescription = contentTypeLanguageLine.ContentTypeDescription,
                    CreateDate = contentTypeLanguageLine.CreateDate,
                    CreatedBy = contentTypeLanguageLine.CreatedBy,
                    UpdateDate = contentTypeLanguageLine.UpdateDate,
                    UpdatedBy = contentTypeLanguageLine.UpdatedBy,
                    DisplayOrder = contentTypeLanguageLine.DisplayOrder,
                    IsApproved = contentTypeLanguageLine.IsApproved,
                    VersionNo = 1,
                    RestoreVersionNo = 0,
                    IsDeleted = false
                });
            }
            _historyRepository.Add(new ContentTypeHistory
            {
                ContentTypeId = affectedItem.Id,
                CreateDate = affectedItem.CreateDate,
                CreatedBy = affectedItem.CreatedBy,
                UpdateDate = affectedItem.UpdateDate,
                UpdatedBy = affectedItem.UpdatedBy,
                VersionNo = 1,
                RestoreVersionNo = 0,
                IsDeleted = false
            });
            _repository.Update(affectedItem);
        }
        public UpdateModel<ContentType> Update(int id)
        {
            var item = _repository.Get(e => e.Id == id);
            if (item == null) throw new NotFoundException();
            return new UpdateModel<ContentType>
            {
                Item = item,
                Languages = _languageService.GetAll()
            };
        }
        public void Update(UpdateModel<ContentType> model)
        {
            model.Languages = _languageService.GetAll();
            var validator = new UpdateValidator(model);
            var validationResults = validator.Validate();
            if (!validator.IsValid)
            {
                throw new ValidationException(Resources.InvalidEntityMessage)
                {
                    ValidationResult = validationResults
                };
            }
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            var item = _repository.Get(e => e.Id == model.Item.Id);
            if (item == null) throw new NotFoundException();
            for (var i = 0; i < item.ContentTypeLanguageLines.Count; i++)
            {
                var lineId = Convert.ToInt32(item.ContentTypeLanguageLines[i].Id);
                var lineVersionNo = _lineHistoryRepository.DbSet().Where(e => e.ContentTypeLanguageLineId == lineId).Max(t => t.VersionNo);
                _lineHistoryRepository.Add(new ContentTypeLanguageLineHistory
                {
                    ContentTypeLanguageLineId = item.ContentTypeLanguageLines[i].Id,
                    ContentTypeId = item.ContentTypeLanguageLines[i].ContentTypeId,
                    LanguageId = item.ContentTypeLanguageLines[i].LanguageId,
                    ContentTypeName = item.ContentTypeLanguageLines[i].ContentTypeName,
                    ContentTypeDescription = item.ContentTypeLanguageLines[i].ContentTypeDescription,
                    CreateDate = item.ContentTypeLanguageLines[i].CreateDate,
                    CreatedBy = item.ContentTypeLanguageLines[i].CreatedBy,
                    UpdateDate = DateTime.Now,
                    UpdatedBy = identity.UserId,
                    DisplayOrder = item.ContentTypeLanguageLines[i].DisplayOrder,
                    IsApproved = item.ContentTypeLanguageLines[i].IsApproved,
                    VersionNo = lineVersionNo + 1,
                    RestoreVersionNo = 0,
                    IsDeleted = false
                });
                item.ContentTypeLanguageLines[i].ContentTypeName = model.Item.ContentTypeLanguageLines[i].ContentTypeName;
                item.ContentTypeLanguageLines[i].ContentTypeDescription = model.Item.ContentTypeLanguageLines[i].ContentTypeDescription;
                item.ContentTypeLanguageLines[i].IsApproved = model.Item.ContentTypeLanguageLines[i].IsApproved;
                item.ContentTypeLanguageLines[i].UpdateDate = DateTime.Now;
                item.ContentTypeLanguageLines[i].UpdatedBy = identity.UserId;
            }
            var id = Convert.ToInt32(item.Id);
            var versionNo = _historyRepository.DbSet().Where(e => e.ContentTypeId == id).Max(t => t.VersionNo);
            _historyRepository.Add(new ContentTypeHistory
            {
                ContentTypeId = item.Id,
                CreateDate = item.CreateDate,
                CreatedBy = item.CreatedBy,
                UpdateDate = DateTime.Now,
                UpdatedBy = identity.UserId,
                VersionNo = versionNo + 1,
                RestoreVersionNo = 0,
                IsDeleted = false
            });
            item.UpdateDate = DateTime.Now;
            item.UpdatedBy = identity.UserId;
            _repository.Update(item);
        }
        public DetailModel<ContentType> Detail(int id)
        {
            var item = _repository.Get(e => e.Id == id);
            if (item == null) throw new NotFoundException();
            return new DetailModel<ContentType>
            {
                Item = item,
                Languages = _languageService.GetAll()
            };
        }
        public void Delete(int id)
        {
            var item = _repository.Get(e => e.Id == id);
            if (item == null) return;
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
            foreach (var contentTypeLanguageLine in item.ContentTypeLanguageLines)
            {
                var lineId = Convert.ToInt32(contentTypeLanguageLine.Id);
                var lineVersionNo = _lineHistoryRepository.DbSet().Where(e => e.ContentTypeLanguageLineId == lineId).Max(t => t.VersionNo);
                _lineHistoryRepository.Add(new ContentTypeLanguageLineHistory
                {
                    ContentTypeLanguageLineId = contentTypeLanguageLine.Id,
                    ContentTypeId = contentTypeLanguageLine.ContentTypeId,
                    LanguageId = contentTypeLanguageLine.LanguageId,
                    ContentTypeName = contentTypeLanguageLine.ContentTypeName,
                    ContentTypeDescription = contentTypeLanguageLine.ContentTypeDescription,
                    CreateDate = contentTypeLanguageLine.CreateDate,
                    CreatedBy = contentTypeLanguageLine.CreatedBy,
                    UpdateDate = DateTime.Now,
                    UpdatedBy = identity.UserId,
                    DisplayOrder = contentTypeLanguageLine.DisplayOrder,
                    IsApproved = contentTypeLanguageLine.IsApproved,
                    VersionNo = lineVersionNo + 1,
                    RestoreVersionNo = 0,
                    IsDeleted = true
                });
            }
            var versionNo = _historyRepository.DbSet().Where(e => e.ContentTypeId == id).Max(t => t.VersionNo);
            _historyRepository.Add(new ContentTypeHistory
            {
                ContentTypeId = item.Id,
                CreateDate = item.CreateDate,
                CreatedBy = item.CreatedBy,
                UpdateDate = DateTime.Now,
                UpdatedBy = identity.UserId,
                VersionNo = versionNo + 1,
                RestoreVersionNo = 0,
                IsDeleted = true
            });
            _repository.Delete(item);
        }       
        public ListModel<ContentType> GetList(ListModel<ContentType> model)
        {
            model.Languages = _languageService.GetAll();
            var selectedLanguageCode = model.SelectedLanguageCode;
            if (model.IdsForDelete != null)
            {
                var ids = model.IdsForDelete;
                ids = ids.Remove(ids.Length - 1);
                var idArray = ids.Split(',');
                var idList = idArray.Select(id => id.ConvertToInt()).ToList();
                DeleteSelected(idList, selectedLanguageCode);
            }
            model.IdsForDelete = null;

            if (model.IdsForApprove != null)
            {
                var ids = model.IdsForApprove;
                ids = ids.Remove(ids.Length - 1);
                var idArray = ids.Split(',');
                var idList = idArray.Select(id => id.ConvertToInt()).ToList();
                ApproveSelected(idList, selectedLanguageCode);
            }
            model.IdsForApprove = null;
            if (model.SelectedStatus != -1)
            {
                var selectedStatus = model.SelectedStatus.ToString().ConvertToBoolean();
                if (model.Searched != null)
                {
                    if (selectedStatus)
                    {
                        model.Where = c => c.ContentTypeLanguageLines.All(t => t.IsApproved && t.ContentTypeName.Contains(model.Searched));
                    }
                    else
                    {
                        model.Where = c => c.ContentTypeLanguageLines.All(t => t.IsApproved == false && t.ContentTypeName.Contains(model.Searched));
                    }
                }
                else
                {
                    if (selectedStatus)
                    {
                        model.Where = c => c.ContentTypeLanguageLines.All(t => t.IsApproved);
                    }
                    else
                    {
                        model.Where = c => c.ContentTypeLanguageLines.All(t => t.IsApproved==false);
                    }
                }
            }
            else
            {
                if (model.Searched != null)
                {
                    model.Where = c => c.ContentTypeLanguageLines.All(t => t.ContentTypeName.Contains(model.Searched));
                }
                else
                {
                    model.Where = c => c.ContentTypeLanguageLines.All(t=>t.Id>0);
                }
            }

            model.Paging.TotalItemCount = _repository.GetCount(model.Where);

            if (model.Paging.CurrentPageSize > 0)
            {
                var sortHelper = new SortHelper<ContentType>();
                sortHelper.OrderByDescending(t => t.ContentTypeLanguageLines.FirstOrDefault(e => e.Language.LanguageCode == selectedLanguageCode).DisplayOrder);
                model.ItemList = _repository.GetList(model.Where, sortHelper, model.Paging.CurrentPage, model.Paging.CurrentPageSize);
            }
            else
            {
                model.ItemList = _repository.GetList(model.Where);
            }
            var pageSizeListSetting = _settingService.GetValueByKey("PageSizeList");
            var pageSizeSettingValue = "10,25,50,100";
            if (pageSizeListSetting != null)
            {
                pageSizeSettingValue = pageSizeListSetting;
            }
            var pageSizeList = pageSizeSettingValue.Split(',').Select(t => new KeyValuePair<int, string>(t.ConvertToInt(), t)).ToList();
            pageSizeList.Insert(0, new KeyValuePair<int, string>(-1, "[" + Resources.All + "]"));
            model.Paging.PageSizeList = pageSizeList;
            if (model.IdsForSort != null)
            {
                var ids = model.IdsForSort;
                ids = ids.Remove(ids.Length - 1);
                var idArray = ids.Split(',');
                var idList = idArray.Select(id => id.ConvertToInt()).ToList();
                model.ItemList = SaveSort(idList, selectedLanguageCode);
            }
            model.IdsForSort = null;

            model.Paging.TotalPageCount = (int)Math.Ceiling((float)model.Paging.TotalItemCount / model.Paging.CurrentPageSize);
            return model;
        }
        private List<ContentType> SaveSort(IReadOnlyList<int> idList, string languageCode)
        {
            var list = new List<ContentType>();
            for (var displayOrder = 0; displayOrder < idList.Count; displayOrder++)
            {
                var id = idList[displayOrder];
                var item = _repository.Get(e => e.Id == id);
                var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;

                for (var i = 0; i < item.ContentTypeLanguageLines.Count; i++)
                {
                    if (item.ContentTypeLanguageLines[i].Language.LanguageCode != languageCode) continue;
                    var lineId = Convert.ToInt32(item.ContentTypeLanguageLines[i].Id);
                    var lineVersionNo = _lineHistoryRepository.DbSet().Where(e => e.ContentTypeLanguageLineId == lineId).Max(t => t.VersionNo);
                    _lineHistoryRepository.Add(new ContentTypeLanguageLineHistory
                    {
                        ContentTypeLanguageLineId = item.ContentTypeLanguageLines[i].Id,
                        ContentTypeId = item.ContentTypeLanguageLines[i].ContentTypeId,
                        LanguageId = item.ContentTypeLanguageLines[i].LanguageId,
                        ContentTypeName = item.ContentTypeLanguageLines[i].ContentTypeName,
                        ContentTypeDescription = item.ContentTypeLanguageLines[i].ContentTypeDescription,
                        CreateDate = item.ContentTypeLanguageLines[i].CreateDate,
                        CreatedBy = item.ContentTypeLanguageLines[i].CreatedBy,
                        UpdateDate = DateTime.Now,
                        UpdatedBy = identity.UserId,
                        DisplayOrder = item.ContentTypeLanguageLines[i].DisplayOrder,
                        IsApproved = item.ContentTypeLanguageLines[i].IsApproved,
                        VersionNo = lineVersionNo + 1,
                        RestoreVersionNo = 0,
                        IsDeleted = false
                    });

                    item.ContentTypeLanguageLines[i].UpdateDate = DateTime.Now;
                    item.ContentTypeLanguageLines[i].UpdatedBy = identity.UserId;
                    item.ContentTypeLanguageLines[i].DisplayOrder = displayOrder + 1;
                }
                var versionNo = _historyRepository.DbSet().Where(e => e.ContentTypeId == id).Max(t => t.VersionNo);
                _historyRepository.Add(new ContentTypeHistory
                {
                    ContentTypeId = item.Id,
                    CreateDate = item.CreateDate,
                    CreatedBy = item.CreatedBy,
                    UpdateDate = DateTime.Now,
                    UpdatedBy = identity.UserId,
                    VersionNo = versionNo + 1,
                    RestoreVersionNo = 0,
                    IsDeleted = false
                });
                item.UpdateDate = DateTime.Now;
                item.UpdatedBy = identity.UserId;

                var z = _repository.Update(item);

                list.Add(z);
            }
            return list;

        }
        private void ApproveSelected(IEnumerable<int> idList, string languageCode)
        {
            foreach (var id in idList)
            {
                var item = _repository.Get(e => e.Id == id);
                var line = item?.ContentTypeLanguageLines.FirstOrDefault(e => e.Language.LanguageCode == languageCode);
                if (line == null) continue;
                var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;
                var lineId = Convert.ToInt32(line.Id);
                var lineVersionNo = _lineHistoryRepository.DbSet().Where(e => e.ContentTypeLanguageLineId == lineId).Max(t => t.VersionNo);


                _lineHistoryRepository.Add(new ContentTypeLanguageLineHistory
                {
                    ContentTypeLanguageLineId = line.Id,
                    ContentTypeId = line.ContentTypeId,
                    LanguageId = line.LanguageId,
                    ContentTypeName = line.ContentTypeName,
                    ContentTypeDescription = line.ContentTypeDescription,
                    CreateDate = line.CreateDate,
                    CreatedBy = line.CreatedBy,
                    UpdateDate = DateTime.Now,
                    UpdatedBy = identity.UserId,
                    DisplayOrder = line.DisplayOrder,
                    IsApproved = line.IsApproved,
                    VersionNo = lineVersionNo + 1,
                    RestoreVersionNo = 0,
                    IsDeleted = false
                });



                item.ContentTypeLanguageLines.FirstOrDefault(e => e.Id == line.Id).UpdateDate = DateTime.Now;
                item.ContentTypeLanguageLines.FirstOrDefault(e => e.Id == line.Id).UpdatedBy = identity.UserId;
                item.ContentTypeLanguageLines.FirstOrDefault(e => e.Id == line.Id).IsApproved = true;

                var versionNo = _historyRepository.DbSet().Where(e => e.ContentTypeId == id).Max(t => t.VersionNo);
                _historyRepository.Add(new ContentTypeHistory
                {
                    ContentTypeId = item.Id,
                    CreateDate = item.CreateDate,
                    CreatedBy = item.CreatedBy,
                    UpdateDate = DateTime.Now,
                    UpdatedBy = identity.UserId,
                    VersionNo = versionNo + 1,
                    RestoreVersionNo = 0,
                    IsDeleted = false
                });
                item.UpdateDate = DateTime.Now;
                item.UpdatedBy = identity.UserId;
                _repository.Update(item);
            }
        }
        private void DeleteSelected(IEnumerable<int> idList, string languageCode)
        {
            foreach (var id in idList)
            {
                Delete(id, languageCode);
            }
        }     
        public void Delete(int id, string languageCode)
        {
            var item = _repository.Get(e=>e.Id==id);
            var line = item?.ContentTypeLanguageLines.FirstOrDefault(e => e.Language.LanguageCode == languageCode);
            if (line == null) return;
            var identity = (TurquoiseIdentity)Thread.CurrentPrincipal.Identity;

            var lineId = Convert.ToInt32(line.Id);
            var lineVersionNo = _lineHistoryRepository.DbSet().Where(e => e.ContentTypeLanguageLineId == lineId).Max(t => t.VersionNo);
            _lineHistoryRepository.Add(new ContentTypeLanguageLineHistory
            {
                ContentTypeLanguageLineId = line.Id,
                ContentTypeId = line.ContentTypeId,
                LanguageId = line.LanguageId,
                ContentTypeName = line.ContentTypeName,
                ContentTypeDescription = line.ContentTypeDescription,
                CreateDate = line.CreateDate,
                CreatedBy = line.CreatedBy,
                UpdateDate = DateTime.Now,
                UpdatedBy = identity.UserId,
                DisplayOrder = line.DisplayOrder,
                IsApproved = line.IsApproved,
                VersionNo = lineVersionNo + 1,
                RestoreVersionNo = 0,
                IsDeleted = true
            });

            var versionNo = _historyRepository.DbSet().Where(e => e.ContentTypeId == id).Max(t => t.VersionNo);
            _historyRepository.Add(new ContentTypeHistory
            {
                ContentTypeId = item.Id,
                CreateDate = item.CreateDate,
                CreatedBy = item.CreatedBy,
                UpdateDate = DateTime.Now,
                UpdatedBy = identity.UserId,
                VersionNo = versionNo + 1,
                RestoreVersionNo = 0,
                IsDeleted = true
            });
            _repository.Delete(item);
        }
    }
}
